package com.redhat.redwork.widget.grid;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import com.dayatang.domain.BaseEntityRepository;

/**
 * adapter class for GridModel
 * 
 * @author Justin
 * 
 * @param <Entity>
 * @param <ID>
 */
public abstract class AbstractGridModel<Entity, C> implements
		GridModel<Entity, C> {

	protected Class<Entity> entityType;
	protected Class<C> criteriaType;
	
	protected BaseEntityRepository repository;
	protected SessionFactory sessionFactory;
	
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * 尝试获取泛型信息
	 */
	@SuppressWarnings("unchecked")
	public AbstractGridModel() {
		Type genType = this.getClass().getGenericSuperclass();
		if(genType instanceof ParameterizedType){
			Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
			this.entityType = (Class<Entity>) params[0];
			this.criteriaType = (Class<C>) params[1];
		}
	}

	/**
	 * 获取查询DTO对象
	 */
	@Override
	public C getCriteriaObject() {
		try {
			return criteriaType.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	@Override
	public Long count(C search) {
		Session session = sessionFactory.openSession();
		try{
			Criteria criteria = session.createCriteria(entityType);
			if(search != null) {
				criteria.add(
					Example.create(search)
					.enableLike(MatchMode.ANYWHERE)
					.excludeZeroes());
			}
			criteria.setProjection(Projections.rowCount());
			List result = criteria.list();
			Long count = ((Number) result.iterator().next()).longValue();
			return count;
		}catch(Throwable t){
			throw new RuntimeException(t);
		}finally{
			session.close();
		}
	}

	@Override
	public void delete(String sid) {
		Long id = Long.parseLong(sid);
		Session session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		try{
			Object entity = session.load(entityType, id);
			if(entity != null){
				session.delete(entity);
			}
			transaction.commit();
		}catch(Throwable t){
			transaction.rollback();
			throw new RuntimeException(t);
		}finally{
			session.close();
		}
	}

	@Override
	public Entity get(String sid) {
		return (Entity) sessionFactory.openSession().createCriteria(entityType).add(Restrictions.eq("id", sid)).uniqueResult();
	}

	/**
	 * QBE enableLike(MatchMode.ANYWHERE) excludeZeroes()
	 */
	@Override
	public List<Entity> list(C search, int page, int pageSize, Order order) {
		Session session = sessionFactory.openSession();
		try{
			Criteria criteria = session.createCriteria(entityType);
			if(search != null) {
				criteria.add(
					Example.create(search)
					.enableLike(MatchMode.ANYWHERE)
					.excludeZeroes());
			}
			return criteria.list();
		}catch(Throwable t){
			throw new RuntimeException(t);
		}finally{
			session.close();
		}
	}

	@Override
	public Entity save(Entity entity) {
		Session session = sessionFactory.openSession();
		try{
			session.save(entity);
		}catch(Throwable t){
			throw new RuntimeException(t);
		}finally{
			session.close();
		}
		session.close();
		return entity;
	}

	@Override
	public Entity update(Entity entity) {
		Session session = sessionFactory.openSession();
		try{
			session.update(entity);
		}catch(Throwable t){
			throw new RuntimeException(t);
		}finally{
			session.close();
		}
		return entity;
	}

}
